import asyncio
import logging
from pathlib import Path

from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage, SimpleEventIsolation
from aiogram.fsm.storage.redis import DefaultKeyBuilder, RedisStorage
from aiogram_dialog import setup_dialogs
from arq import create_pool

from src.bot.dialogs import register_dialogs
from src.bot.handlers import register_handlers
from src.bot.middlewares.db import DBSessionMiddleware
from src.bot.middlewares.locale import LocaleMiddleware
from src.bot.services.locale import Localizator, configure_localizator
from src.bot.services.tg_helpers import send_tg_message
from src.config import load_config
from src.core.logger import configure_logging
from src.core.payment_client.client import FondyPaymentClient
from src.database.main import build_sa_engine, build_sa_session_factory

logger = logging.getLogger(__name__)


def setup_middlewares(
    dp: Dispatcher,
    session_factory,
    localizator: Localizator,
):
    dp.callback_query.outer_middleware(DBSessionMiddleware(session_factory))
    dp.update.outer_middleware(DBSessionMiddleware(session_factory))
    dp.message.outer_middleware.register(LocaleMiddleware(localizator))
    dp.errors.outer_middleware.register(LocaleMiddleware(localizator))
    dp.update.outer_middleware(LocaleMiddleware(localizator))
    dp.callback_query.outer_middleware.register(LocaleMiddleware(localizator))


async def main():
    config = load_config()
    configure_logging()

    if config.tg_bot.use_redis:
        storage = RedisStorage.from_url(
            url=config.redis.url,
            key_builder=DefaultKeyBuilder(with_destiny=True),
        )
    else:
        storage = MemoryStorage()

    bot = Bot(token=config.tg_bot.token, parse_mode="HTML")
    bot_username = await bot.get_me()
    logger.error(f"Starting bot {bot_username}")

    dp = Dispatcher(storage=storage, events_isolation=SimpleEventIsolation())
    engine = build_sa_engine(config.db)
    fondy = FondyPaymentClient(config.fondy.api_token, config.fondy.shop_id)
    session_factory = build_sa_session_factory(engine)
    localizator = configure_localizator(Path(__file__).parent / Path("locales/"))
    redis_pool = await create_pool(config.redis.pool_settings)

    setup_middlewares(dp, session_factory, localizator)

    setup_dialogs(dp)
    register_handlers(dp, config)
    register_dialogs(dp)

    await send_tg_message(bot, config.tg_bot.developer_id, "Бот запущен!")
    try:
        await dp.start_polling(bot, arqredis=redis_pool, config=config, fondy=fondy)
    finally:
        await engine.dispose()


def cli():
    try:
        asyncio.run(main())
    except (KeyboardInterrupt, SystemExit):
        logger.error("Bot stopped!")


if __name__ == "__main__":
    cli()
